package com.liu.audio.domain;

import javax.sound.sampled.*;
import java.nio.ByteBuffer;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;

public class PlaybackRunnable implements Runnable {
        // Set the audio format. Please configure according to your actual device,
        // synthesized audio parameters, and platform choice Here it is set to
        // 22050Hz16bit single channel. It is recommended that customers choose other
        // sample rates and formats based on the model sample rate and device
        // compatibility.

        // 设置音频格式，请根据实际自身设备，合成音频参数和平台选择配置
        // 这里选择48k16bit单通道，建议客户根据选用的模型采样率情况和自身设备兼容性选择其他采样率和格式
        private AudioFormat af = new AudioFormat(22050, 16, 1, true, false);
        private DataLine.Info info = new DataLine.Info(SourceDataLine.class, af);
        private SourceDataLine targetSource = null;
        private AtomicBoolean runFlag = new AtomicBoolean(true);
        private ConcurrentLinkedQueue<ByteBuffer> queue = new ConcurrentLinkedQueue<>();

        public PlaybackRunnable() throws LineUnavailableException {
            targetSource = (SourceDataLine) AudioSystem.getLine(info);
            targetSource.open(af, 4096);
            targetSource.start();
        }


        public void put(ByteBuffer buffer) {
            queue.add(buffer);
        }

        // Stop playback
        public void stop() {
            runFlag.set(false);
        }

        @Override
        public void run() {
            if (targetSource == null) {
                return;
            }

            while (runFlag.get()) {
                if (queue.isEmpty()) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                    }
                    continue;
                }

                ByteBuffer buffer = queue.poll();
                if (buffer == null) {
                    continue;
                }


                byte[] data = buffer.array();
                targetSource.write(data, 0, data.length);
            }

            // Play all remaining cache
            if (!queue.isEmpty()) {
                ByteBuffer buffer = null;
                while ((buffer = queue.poll()) != null) {
                    byte[] data = buffer.array();
                    targetSource.write(data, 0, data.length);
                }


            }

            // Release the player
            targetSource.drain();
            targetSource.stop();
            targetSource.close();
        }
    }